home *** CD-ROM | disk | FTP | other *** search
/ MPEG Toolkit / MPEG Toolkit.iso / os2 / mpegenc / src / bframe.c next >
Encoding:
C/C++ Source or Header  |  1997-01-01  |  30.1 KB  |  1,055 lines

  1. /*===========================================================================*
  2.  * bframe.c                                     *
  3.  *                                         *
  4.  *    Procedures concerned with the B-frame encoding                 *
  5.  *                                         *
  6.  * EXPORTED PROCEDURES:                                 *
  7.  *    GenBFrame                                 *
  8.  *    ResetBFrameStats                             *
  9.  *    ShowBFrameSummary                             *
  10.  *    EstimateSecondsPerBFrame                         *
  11.  *    ComputeBMotionLumBlock                             *
  12.  *    SetBQScale                                 *
  13.  *    GetBQScale                                 *
  14.  *                                         *
  15.  *===========================================================================*/
  16.  
  17. /*
  18.  * Copyright (c) 1993 The Regents of the University of California.
  19.  * All rights reserved.
  20.  *
  21.  * Permission to use, copy, modify, and distribute this software and its
  22.  * documentation for any purpose, without fee, and without written agreement is
  23.  * hereby granted, provided that the above copyright notice and the following
  24.  * two paragraphs appear in all copies of this software.
  25.  *
  26.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  27.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  28.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  29.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30.  *
  31.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  32.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  33.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  34.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  35.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  36.  */
  37.  
  38. /*  
  39.  *  $Header: /n/picasso/users/keving/encode/src/RCS/bframe.c,v 1.5 1993/07/30 19:24:04 keving Exp keving $
  40.  *  $Log: bframe.c,v $
  41.  * Revision 1.5  1993/07/30  19:24:04  keving
  42.  * nothing
  43.  *
  44.  * Revision 1.4  1993/07/22  22:23:43  keving
  45.  * nothing
  46.  *
  47.  * Revision 1.3  1993/06/30  20:06:09  keving
  48.  * nothing
  49.  *
  50.  * Revision 1.2  1993/06/03  21:08:08  keving
  51.  * nothing
  52.  *
  53.  * Revision 1.1  1993/02/19  19:14:28  keving
  54.  * nothing
  55.  *
  56.  */
  57.  
  58.  
  59. /*==============*
  60.  * HEADER FILES *
  61.  *==============*/
  62.  
  63. #include "all.h"
  64. /* @@@ Fake up 'times' interface under OS/2, Andy Key */
  65. #ifdef OS2
  66. #include "os2port.h"
  67. #else
  68. #include <sys/times.h>
  69. #endif
  70. #include "mtypes.h"
  71. #include "bitio.h"
  72. #include "frames.h"
  73. #ifdef OS2
  74. /* @@@ FAT 8.3 convention */
  75. #include "prototyp.h"
  76. #else
  77. #include "prototypes.h"
  78. #endif
  79. #include "fsize.h"
  80. #include "param.h"
  81. #include "mheaders.h"
  82. #include "postdct.h"
  83.  
  84.  
  85. /*==================*
  86.  * STATIC VARIABLES *
  87.  *==================*/
  88.  
  89. static int numBIBlocks = 0;
  90. static int numBBBlocks = 0;
  91. static int numBSkipped = 0;
  92. static int numBIBits = 0;
  93. static int numBBBits = 0;
  94. static int numFrames = 0;
  95. static int numFrameBits = 0;
  96. static int32 totalTime = 0;
  97. static int qscaleB;
  98. static float    totalSNR = 0.0;
  99. static float    totalPSNR = 0.0;
  100.  
  101.  
  102. /*===============================*
  103.  * INTERNAL PROCEDURE prototypes *
  104.  *===============================*/
  105.  
  106. static boolean    MotionSufficient _ANSI_ARGS_((LumBlock currBlock, MpegFrame *prev, MpegFrame *next,
  107.              int by, int bx, int mode, int fmy, int fmx,
  108.              int bmy, int bmx));
  109. static void    ComputeBMotionBlock _ANSI_ARGS_((MpegFrame *prev, MpegFrame *next,
  110.                    int by, int bx, int mode, int fmy, int fmx,
  111.                    int bmy, int bmx, Block motionBlock, int type));
  112. static void    ComputeBDiffDCTs _ANSI_ARGS_((MpegFrame *current, MpegFrame *prev, MpegFrame *next,
  113.              int by, int bx, int mode, int fmy, int fmx, 
  114.              int bmy, int bmx, int pattern));
  115. static boolean    DoBIntraCode _ANSI_ARGS_((MpegFrame *current, MpegFrame *prev, MpegFrame *next,
  116.              int by, int bx, int mode, int fmy, int fmx, int bmy,
  117.              int bmx));
  118.  
  119.  
  120. /*=====================*
  121.  * EXPORTED PROCEDURES *
  122.  *=====================*/
  123.  
  124. /*===========================================================================*
  125.  *
  126.  * GenBFrame
  127.  *
  128.  *    generate a B-frame from previous and next frames, adding the result
  129.  *    to the given bit bucket
  130.  *
  131.  * RETURNS:    frame appended to bb
  132.  *
  133.  * SIDE EFFECTS:    none
  134.  *
  135.  *===========================================================================*/
  136. void
  137. GenBFrame(bb, curr, prev, next)
  138.     BitBucket *bb;
  139.     MpegFrame *curr;
  140.     MpegFrame *prev;
  141.     MpegFrame *next;
  142. {
  143.     FlatBlock fba[6], fb[6];
  144.     Block    dec[6];
  145.     int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
  146.     int x, y;
  147.     int    fMotionX = 0, fMotionY = 0;
  148.     int bMotionX = 0, bMotionY = 0;
  149.     int    oldFMotionX = 0, oldFMotionY = 0;
  150.     int oldBMotionX = 0, oldBMotionY = 0;
  151.     int    oldMode = MOTION_FORWARD;
  152.     int    mode = MOTION_FORWARD;
  153.     int    offsetX, offsetY;
  154.     int    tempX, tempY;
  155.     int    fMotionXrem = 0, fMotionXquot = 0;
  156.     int    fMotionYrem = 0, fMotionYquot = 0;
  157.     int    bMotionXrem = 0, bMotionXquot = 0;
  158.     int    bMotionYrem = 0, bMotionYquot = 0;
  159.     int    pattern;
  160.     int    numIBlocks = 0;
  161.     int numBBlocks = 0;
  162.     int numSkipped = 0;
  163.     int    numIBits = 0;
  164.     int    numBBits = 0;
  165.     int    totalBits;
  166.     int    mbAddrInc = 1;
  167.     boolean    lastIntra = TRUE;
  168.     int        motionForward, motionBackward;
  169.     int        totalFrameBits;
  170.     struct tms timeBuffer;
  171.     int32    startTime, endTime;
  172.     int lastX, lastY;
  173.     int lastBlockX, lastBlockY;
  174.     register int ix, iy;
  175.     LumBlock currentBlock;
  176.     int fy, fx;
  177.     boolean    result;
  178.     int    frameBlocks;
  179.     int        slicePos;
  180.     float   snr[3], psnr[3];
  181.     int        index;
  182.  
  183.     numFrames++;
  184.     totalFrameBits = bb->cumulativeBits;
  185.     times(&timeBuffer);
  186.     startTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  187.  
  188.     Mhead_GenPictureHeader(bb, B_FRAME, curr->id, fCode);
  189.     Mhead_GenSliceHeader(bb, 1, qscaleB, NULL, 0);
  190.  
  191.     Frame_AllocBlocks(curr);
  192.     BlockifyFrame(curr);
  193.  
  194.     if ( printSNR ) {
  195.     Frame_AllocDecoded(curr, FALSE);
  196.     }
  197.  
  198.     /* for I-blocks */
  199.     y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  200.  
  201.     totalBits = bb->cumulativeBits;
  202.  
  203.     if ( ! pixelFullSearch ) {
  204.     if ( ! prev->halfComputed ) {
  205.         ComputeHalfPixelData(prev);
  206.     }
  207.  
  208.     if ( ! next->halfComputed ) {
  209.         ComputeHalfPixelData(next);
  210.     }
  211.     }
  212.  
  213.     lastBlockX = Fsize_x/8;
  214.     lastBlockY = Fsize_y/8;
  215.     lastX = lastBlockX-2;
  216.     lastY = lastBlockY-2;
  217.     frameBlocks = 0;
  218.  
  219.     for (y = 0; y < lastBlockY; y += 2) {
  220.     for (x = 0; x < lastBlockX; x += 2) {
  221.         slicePos = (frameBlocks % blocksPerSlice);
  222.  
  223.         if ( (slicePos == 0) && (frameBlocks != 0) ) {
  224.         Mhead_GenSliceEnder(bb);
  225.         Mhead_GenSliceHeader(bb, 1+(y/2), qscaleB, NULL, 0);
  226.  
  227.         /* reset everything */
  228.         oldFMotionX = 0;    oldFMotionY = 0;
  229.         oldBMotionX = 0;    oldBMotionY = 0;
  230.         oldMode = MOTION_FORWARD;
  231.         lastIntra = TRUE;
  232.         y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  233.  
  234.         mbAddrInc = 1+(x/2);
  235.         }
  236.  
  237.         frameBlocks++;
  238.  
  239.         /* compute currentBlock */
  240.         BLOCK_TO_FRAME_COORD(y, x, fy, fx);
  241.         for ( iy = 0; iy < 16; iy++ ) {
  242.         for ( ix = 0; ix < 16; ix++ ) {
  243.             currentBlock[iy][ix] = (int16)curr->orig_y[fy+iy][fx+ix];
  244.         }
  245.         }
  246.  
  247. /* STEP 1:  Select Forward, Backward, or Interpolated motion vectors */
  248.         /* see if old motion is good enough */
  249.         /* but force last block to be non-skipped */
  250.         /* can only skip if:
  251.          *     1)  not the last block in frame
  252.          *     2)  not the last block in slice
  253.          *     3)  not the first block in slice
  254.          *       4)  previous block was not intra-coded
  255.          */
  256.         if ( ((y < lastY) || (x < lastX)) &&
  257.          (slicePos+1 != blocksPerSlice) &&
  258.          (slicePos != 0) &&
  259.          (! lastIntra) ) {
  260.         if ( pixelFullSearch ) {
  261.             result = MotionSufficient(currentBlock, prev, next, y, x, oldMode,
  262.                           2*oldFMotionY, 2*oldFMotionX,
  263.                           2*oldBMotionY, 2*oldBMotionX);
  264.         } else {
  265.             result = MotionSufficient(currentBlock, prev, next, y, x, oldMode,
  266.                       oldFMotionY, oldFMotionX,
  267.                       oldBMotionY, oldBMotionX);
  268.         }
  269.         } else {
  270.         result = FALSE;
  271.         }
  272.  
  273.         if ( result ) {
  274.         /* skipped macro block */
  275.         mbAddrInc++;
  276.         numSkipped++;
  277.  
  278.         /* decode skipped block */
  279.         if ( printSNR ) {
  280.             int    fmy, fmx, bmy, bmx;
  281.  
  282.             memset((char *)dec[0], 0, sizeof(Block)); 
  283.             memset((char *)dec[1], 0, sizeof(Block)); 
  284.             memset((char *)dec[2], 0, sizeof(Block)); 
  285.             memset((char *)dec[3], 0, sizeof(Block)); 
  286.             memset((char *)dec[4], 0, sizeof(Block)); 
  287.             memset((char *)dec[5], 0, sizeof(Block)); 
  288.  
  289.             if ( pixelFullSearch ) {
  290.             fmy = 2*oldFMotionY;
  291.             fmx = 2*oldFMotionX;
  292.             bmy = 2*oldBMotionY;
  293.             bmx = 2*oldBMotionX;
  294.             } else {
  295.             fmy = oldFMotionY;
  296.             fmx = oldFMotionX;
  297.             bmy = oldBMotionY;
  298.             bmx = oldBMotionX;
  299.             }
  300.  
  301.             /* now add the motion block */
  302.             AddBMotionBlock(dec[0], prev->decoded_y,
  303.                     next->decoded_y, y, x, mode,
  304.                     fmy, fmx, bmy, bmx);
  305.             AddBMotionBlock(dec[1], prev->decoded_y,
  306.                     next->decoded_y, y, x+1, mode,
  307.                     fmy, fmx, bmy, bmx);
  308.             AddBMotionBlock(dec[2], prev->decoded_y,
  309.                     next->decoded_y, y+1, x, mode,
  310.                     fmy, fmx, bmy, bmx);
  311.             AddBMotionBlock(dec[3], prev->decoded_y,
  312.                     next->decoded_y, y+1, x+1, mode,
  313.                     fmy, fmx, bmy, bmx);
  314.             AddBMotionBlock(dec[4], prev->decoded_cb,
  315.                     next->decoded_cb, y>>1, x>>1, mode,
  316.                     fmy/2, fmx/2,
  317.                     bmy/2, bmx/2);
  318.             AddBMotionBlock(dec[5], prev->decoded_cr,
  319.                     next->decoded_cb, y>>1, x>>1, mode,
  320.                     fmy/2, fmx/2,
  321.                     bmy/2, bmx/2);
  322.  
  323.             /* now, unblockify */
  324.             BlockToData(curr->decoded_y, dec[0], y, x);
  325.             BlockToData(curr->decoded_y, dec[1], y, x+1);
  326.             BlockToData(curr->decoded_y, dec[2], y+1, x);
  327.             BlockToData(curr->decoded_y, dec[3], y+1, x+1);
  328.             BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
  329.             BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
  330.         }
  331.         } else {
  332.         /* do bsearch */
  333.         mode = BMotionSearch(currentBlock, prev, next, y, x, &fMotionY,
  334.                      &fMotionX, &bMotionY, &bMotionX, mode);
  335.  
  336.         pattern = 63;
  337.  
  338. /* STEP 2:  INTRA OR NON-INTRA CODING */
  339.         if ( DoBIntraCode(curr, prev, next, y, x, mode, fMotionY,
  340.                   fMotionX, bMotionY, bMotionX) ) {
  341.             /* output I-block inside a P-frame */
  342.             numIBlocks++;
  343.  
  344.             /* calculate forward dct's */
  345.             mp_fwd_dct_block(curr->y_blocks[y][x]);
  346.             mp_fwd_dct_block(curr->y_blocks[y][x+1]);
  347.             mp_fwd_dct_block(curr->y_blocks[y+1][x]);
  348.             mp_fwd_dct_block(curr->y_blocks[y+1][x+1]);
  349.             mp_fwd_dct_block(curr->cb_blocks[y >> 1][x >> 1]);
  350.             mp_fwd_dct_block(curr->cr_blocks[y >> 1][x >> 1]);
  351.  
  352.             GEN_I_BLOCK(B_FRAME, curr, bb, mbAddrInc, qscaleB);
  353.  
  354.             mbAddrInc = 1;
  355.  
  356.             numIBits += (bb->cumulativeBits-totalBits);
  357.             totalBits = bb->cumulativeBits;
  358.  
  359.             /* reset because intra-coded */
  360.             oldFMotionX = 0;        oldFMotionY = 0;
  361.             oldBMotionX = 0;        oldBMotionY = 0;
  362.             oldMode = MOTION_FORWARD;
  363.             lastIntra = TRUE;
  364.  
  365.             if ( printSNR ) {
  366.             /* need to decode block we just encoded */
  367.             Mpost_UnQuantZigBlock(fb[0], dec[0], qscaleB, TRUE);
  368.             Mpost_UnQuantZigBlock(fb[1], dec[1], qscaleB, TRUE);
  369.             Mpost_UnQuantZigBlock(fb[2], dec[2], qscaleB, TRUE);
  370.             Mpost_UnQuantZigBlock(fb[3], dec[3], qscaleB, TRUE);
  371.             Mpost_UnQuantZigBlock(fb[4], dec[4], qscaleB, TRUE);
  372.             Mpost_UnQuantZigBlock(fb[5], dec[5], qscaleB, TRUE);
  373.  
  374.             /* now, reverse the DCT transform */
  375.             for ( index = 0; index < 6; index++ ) {
  376.                 j_rev_dct((int16 *)dec[index]);
  377.             }
  378.  
  379.             /* now, unblockify */
  380.             BlockToData(curr->decoded_y, dec[0], y, x);
  381.             BlockToData(curr->decoded_y, dec[1], y, x+1);
  382.             BlockToData(curr->decoded_y, dec[2], y+1, x);
  383.             BlockToData(curr->decoded_y, dec[3], y+1, x+1);
  384.             BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
  385.             BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
  386.             }
  387.         } else {
  388. /* STEP 3:  CODED OR NOT CODED */            
  389.             /* make special cases for (0,0) motion???? */
  390.             lastIntra = FALSE;
  391.             /* USE MOTION VECTORS */
  392.             numBBlocks++;
  393.  
  394.             /* reset because non-intra-coded */
  395.             y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
  396.  
  397.             ComputeBDiffDCTs(curr, prev, next, y, x, mode, fMotionY,
  398.                      fMotionX, bMotionY, bMotionX, pattern);
  399.  
  400.             if ( pixelFullSearch ) {
  401.             fMotionX /= 2;        fMotionY /= 2;
  402.             bMotionX /= 2;        bMotionY /= 2;
  403.             }
  404.  
  405. /* should really check to see if same motion as previous block, and see if
  406. pattern is 0, then skip it! */
  407.  
  408.              motionForward = ((mode != MOTION_BACKWARD) ? 1 : 0);
  409.             motionBackward = ((mode != MOTION_FORWARD) ? 1 : 0);
  410.  
  411.             if ( motionForward ) {
  412.             /* transform the fMotion vector into the appropriate values */
  413.             offsetX = fMotionX - oldFMotionX;
  414.             offsetY = fMotionY - oldFMotionY;
  415.  
  416.             ENCODE_MOTION_VECTOR(offsetX, offsetY, fMotionXquot,
  417.                      fMotionYquot, fMotionXrem, fMotionYrem,
  418.                      FORW_F);
  419.  
  420.             oldFMotionX = fMotionX;        oldFMotionY = fMotionY;
  421.             }
  422.  
  423.             if ( motionBackward ) {
  424.             /* transform the bMotion vector into the appropriate values */
  425.             offsetX = bMotionX - oldBMotionX;
  426.             offsetY = bMotionY - oldBMotionY;
  427.             ENCODE_MOTION_VECTOR(offsetX, offsetY, bMotionXquot,
  428.                      bMotionYquot, bMotionXrem, bMotionYrem,
  429.                      BACK_F);
  430.  
  431.             oldBMotionX = bMotionX;        oldBMotionY = bMotionY;
  432.             }
  433.  
  434.             oldMode = mode;
  435.  
  436.             if ( pixelFullSearch ) {
  437.             fMotionX *= 2;    fMotionY *= 2;
  438.             bMotionX *= 2;    bMotionY *= 2;
  439.             }
  440.  
  441.         /* create flat blocks and update pattern if necessary */
  442.     if ( (pattern & 0x20) && 
  443.          (! Mpost_QuantZigBlock(curr->y_blocks[y][x], fba[0],
  444.                    qscaleB, FALSE)) ) {
  445.         pattern ^= 0x20;
  446.     }
  447.     if ( (pattern & 0x10) && 
  448.          (! Mpost_QuantZigBlock(curr->y_blocks[y][x+1], fba[1],
  449.                    qscaleB, FALSE)) ) {
  450.         pattern ^= 0x10;
  451.     }
  452.     if ( (pattern & 0x8) && 
  453.          (! Mpost_QuantZigBlock(curr->y_blocks[y+1][x], fba[2],
  454.                    qscaleB, FALSE)) ) {
  455.         pattern ^= 0x8;
  456.     }
  457.     if ( (pattern & 0x4) && 
  458.          (! Mpost_QuantZigBlock(curr->y_blocks[y+1][x+1], fba[3],
  459.                    qscaleB, FALSE)) ) {
  460.         pattern ^= 0x4;
  461.     }
  462.     if ( (pattern & 0x2) && 
  463.          (! Mpost_QuantZigBlock(curr->cb_blocks[y >> 1][x >> 1], fba[4],
  464.                    qscaleB, FALSE)) ) {
  465.         pattern ^= 0x2;
  466.     }
  467.     if ( (pattern & 0x1) && 
  468.          (! Mpost_QuantZigBlock(curr->cr_blocks[y >> 1][x >> 1], fba[5],
  469.                    qscaleB, FALSE)) ) {
  470.         pattern ^= 0x1;
  471.     }
  472.  
  473.             if ( printSNR ) {
  474.             if ( pattern & 0x20 ) {
  475.                 Mpost_UnQuantZigBlock(fba[0], dec[0], qscaleB, FALSE);
  476.             } else {
  477.                 memset((char *)dec[0], 0, sizeof(Block));
  478.             }
  479.             if ( pattern & 0x10 ) {
  480.                 Mpost_UnQuantZigBlock(fba[1], dec[1], qscaleB, FALSE);
  481.             } else {
  482.                 memset((char *)dec[1], 0, sizeof(Block));
  483.             }
  484.             if ( pattern & 0x8 ) {
  485.                 Mpost_UnQuantZigBlock(fba[2], dec[2], qscaleB, FALSE);
  486.             } else {
  487.                 memset((char *)dec[2], 0, sizeof(Block));
  488.             }
  489.             if ( pattern & 0x4 ) {
  490.                 Mpost_UnQuantZigBlock(fba[3], dec[3], qscaleB, FALSE);
  491.             } else {
  492.                 memset((char *)dec[3], 0, sizeof(Block));
  493.             }
  494.             if ( pattern & 0x2 ) {
  495.                 Mpost_UnQuantZigBlock(fba[4], dec[4], qscaleB, FALSE);
  496.             } else {
  497.                 memset((char *)dec[4], 0, sizeof(Block));
  498.             }
  499.             if ( pattern & 0x1 ) {
  500.                 Mpost_UnQuantZigBlock(fba[5], dec[5], qscaleB, FALSE);
  501.             } else {
  502.                 memset((char *)dec[5], 0, sizeof(Block));
  503.             }
  504.  
  505.             /* now, reverse the DCT transform */
  506.             for ( index = 0; index < 6; index++ ) {
  507.                 if ( GET_ITH_BIT(pattern, 5-index) ) {
  508.                 j_rev_dct((int16 *)dec[index]);
  509.                 }
  510.             }
  511.  
  512.             /* now add the motion block */
  513.             AddBMotionBlock(dec[0], prev->decoded_y,
  514.                     next->decoded_y, y, x, mode,
  515.                     fMotionY, fMotionX, bMotionY, bMotionX);
  516.             AddBMotionBlock(dec[1], prev->decoded_y,
  517.                     next->decoded_y, y, x+1, mode,
  518.                     fMotionY, fMotionX, bMotionY, bMotionX);
  519.             AddBMotionBlock(dec[2], prev->decoded_y,
  520.                     next->decoded_y, y+1, x, mode,
  521.                     fMotionY, fMotionX, bMotionY, bMotionX);
  522.             AddBMotionBlock(dec[3], prev->decoded_y,
  523.                     next->decoded_y, y+1, x+1, mode,
  524.                     fMotionY, fMotionX, bMotionY, bMotionX);
  525.             AddBMotionBlock(dec[4], prev->decoded_cb,
  526.                     next->decoded_cb, y>>1, x>>1, mode,
  527.                     fMotionY/2, fMotionX/2,
  528.                     bMotionY/2, bMotionX/2);
  529.             AddBMotionBlock(dec[5], prev->decoded_cr,
  530.                     next->decoded_cr, y>>1, x>>1, mode,
  531.                     fMotionY/2, fMotionX/2,
  532.                     bMotionY/2, bMotionX/2);
  533.  
  534.             /* now, unblockify */
  535.             BlockToData(curr->decoded_y, dec[0], y, x);
  536.             BlockToData(curr->decoded_y, dec[1], y, x+1);
  537.             BlockToData(curr->decoded_y, dec[2], y+1, x);
  538.             BlockToData(curr->decoded_y, dec[3], y+1, x+1);
  539.             BlockToData(curr->decoded_cb, dec[4], y>>1, x>>1);
  540.             BlockToData(curr->decoded_cr, dec[5], y>>1, x>>1);
  541.             }
  542.  
  543.         DBG_PRINT(("MB Header(%d,%d)\n", x, y));
  544.         Mhead_GenMBHeader(bb, 3 /* pict_code_type */, mbAddrInc /* addr_incr */,
  545.               0 /* mb_quant */, 0 /* q_scale */,
  546.               fCode /* forw_f_code */, fCode /* back_f_code */,
  547.               fMotionXrem /* horiz_forw_r */, fMotionYrem /* vert_forw_r */,
  548.               bMotionXrem /* horiz_back_r */, bMotionYrem /* vert_back_r */,
  549.               motionForward /* motion_forw */, fMotionXquot /* m_horiz_forw */,
  550.               fMotionYquot /* m_vert_forw */, motionBackward /* motion_back */,
  551.               bMotionXquot /* m_horiz_back */, bMotionYquot /* m_vert_back */,
  552.               pattern /* mb_pattern */, 0 /* mb_intra */);
  553.             mbAddrInc = 1;
  554.  
  555.         /* now output the difference */
  556.         for ( tempX = 0; tempX < 6; tempX++ ) {
  557.             if ( GET_ITH_BIT(pattern, 5-tempX) ) {
  558.             Mpost_RLEHuffPBlock(fba[tempX], bb);
  559.             }
  560.         }
  561.  
  562.             numBBits += (bb->cumulativeBits-totalBits);
  563.             totalBits = bb->cumulativeBits;
  564.         }
  565.         }
  566.     }
  567.     }
  568.  
  569.     if ( printSNR ) {
  570.         ComputeSNR(curr->orig_y, curr->decoded_y, Fsize_y, Fsize_x,
  571.            &snr[0], &psnr[0]);
  572.         ComputeSNR(curr->orig_cb, curr->decoded_cb, Fsize_y/2, Fsize_x/2,
  573.            &snr[1], &psnr[1]);
  574.         ComputeSNR(curr->orig_cr, curr->decoded_cr, Fsize_y/2, Fsize_x/2,
  575.            &snr[2], &psnr[2]);
  576.  
  577.     totalSNR += snr[0];
  578.     totalPSNR += psnr[0];
  579.     }
  580.  
  581.     Mhead_GenSliceEnder(bb);
  582.  
  583.     times(&timeBuffer);
  584.     endTime = timeBuffer.tms_utime + timeBuffer.tms_stime;
  585.     totalTime += (endTime-startTime);
  586.  
  587.     if ( (! childProcess) && frameSummary ) {
  588.     fprintf(stdout, "FRAME %d (B):  I BLOCKS:  %d;  B BLOCKS:  %d   SKIPPED:  %d (%ld seconds)\n",
  589.         curr->id, numIBlocks, numBBlocks, numSkipped, (long)((endTime-startTime)/60));
  590.     if ( printSNR )
  591.         fprintf(stdout, "FRAME %d:  SNR:  %.1f\t%.1f\t%.1f\tPSNR:  %.1f\t%.1f\t%.1f\n",
  592.             curr->id, snr[0], snr[1], snr[2],
  593.             psnr[0], psnr[1], psnr[2]);
  594.     }
  595.  
  596.     numFrameBits += (bb->cumulativeBits-totalFrameBits);
  597.     numBIBlocks += numIBlocks;
  598.     numBBBlocks += numBBlocks;
  599.     numBSkipped += numSkipped;
  600.     numBIBits += numIBits;
  601.     numBBBits += numBBits;
  602. }
  603.  
  604.  
  605. /*===========================================================================*
  606.  *
  607.  * SetBQScale
  608.  *
  609.  *    set the B-frame Q-scale
  610.  *
  611.  * RETURNS:    nothing
  612.  *
  613.  * SIDE EFFECTS:    qscaleB
  614.  *
  615.  *===========================================================================*/
  616. void
  617. SetBQScale(qB)
  618.     int qB;
  619. {
  620.     qscaleB = qB;
  621. }
  622.  
  623.  
  624. /*===========================================================================*
  625.  *
  626.  * GetBQScale
  627.  *
  628.  *    get the B-frame Q-scale
  629.  *
  630.  * RETURNS:    the Q-scale
  631.  *
  632.  * SIDE EFFECTS:    none
  633.  *
  634.  *===========================================================================*/
  635. int
  636. GetBQScale()
  637. {
  638.     return qscaleB;
  639. }
  640.  
  641.  
  642. /*===========================================================================*
  643.  *
  644.  * ResetBFrameStats
  645.  *
  646.  *    reset the B-frame stats
  647.  *
  648.  * RETURNS:    nothing
  649.  *
  650.  * SIDE EFFECTS:    none
  651.  *
  652.  *===========================================================================*/
  653. void
  654. ResetBFrameStats()
  655. {
  656.     numBIBlocks = 0;
  657.     numBBBlocks = 0;
  658.     numBSkipped = 0;
  659.     numBIBits = 0;
  660.     numBBBits = 0;
  661.     numFrames = 0;
  662.     numFrameBits = 0;
  663.     totalTime = 0;
  664. }
  665.  
  666.  
  667. /*===========================================================================*
  668.  *
  669.  * ShowBFrameSummary
  670.  *
  671.  *    print out statistics on all B-frames
  672.  *
  673.  * RETURNS:    nothing
  674.  *
  675.  * SIDE EFFECTS:    none
  676.  *
  677.  *===========================================================================*/
  678. void
  679. ShowBFrameSummary(inputFrameBits, totalBits, fpointer)
  680.     int inputFrameBits;
  681.     int32 totalBits;
  682.     FILE *fpointer;
  683. {
  684.     if ( numFrames == 0 ) {
  685.     return;
  686.     }
  687.  
  688.     fprintf(fpointer, "-------------------------\n");
  689.     fprintf(fpointer, "*****B FRAME SUMMARY*****\n");
  690.     fprintf(fpointer, "-------------------------\n");
  691.  
  692.     if ( numBIBlocks != 0 ) {
  693.     fprintf(fpointer, "  I Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
  694.         numBIBlocks, numBIBits, numBIBits/numBIBlocks);
  695.     } else {
  696.     fprintf(fpointer, "  I Blocks:  %5d\n", 0);
  697.     }
  698.  
  699.     if ( numBBBlocks != 0 ) {
  700.     fprintf(fpointer, "  B Blocks:  %5d     (%6d bits)     (%5d bpb)\n",
  701.         numBBBlocks, numBBBits, numBBBits/numBBBlocks);
  702.     } else {
  703.     fprintf(fpointer, "  B Blocks:  %5d\n", 0);
  704.     }
  705.  
  706.     fprintf(fpointer, "  Skipped:   %5d\n", numBSkipped);
  707.  
  708.     fprintf(fpointer, "  Frames:    %5d     (%6d bits)     (%5d bpf)     (%2.1f%% of total)\n",
  709.         numFrames, numFrameBits, numFrameBits/numFrames,
  710.         100.0*(float)numFrameBits/(float)totalBits);        
  711.     fprintf(fpointer, "  Compression:  %3d:1\n",
  712.         numFrames*inputFrameBits/numFrameBits);
  713.     if ( printSNR )
  714.     fprintf(fpointer, "  Avg Y SNR/PSNR:  %.1f     %.1f\n",
  715.         totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
  716.     fprintf(fpointer, "  Seconds:  %9ld     (%9ld spf)     (%9ld bps)\n",
  717.         (long)(totalTime/60), (long)(totalTime/(60*numFrames)),
  718.         (long)(60.0*(float)numFrames*(float)inputFrameBits/(float)totalTime));
  719. }
  720.  
  721.  
  722. /*===========================================================================*
  723.  *
  724.  * ComputeBMotionLumBlock
  725.  *
  726.  *    compute the luminance block resulting from motion compensation
  727.  *
  728.  * RETURNS:    motionBlock modified
  729.  *
  730.  * SIDE EFFECTS:    none
  731.  *
  732.  * PRECONDITION:    the motion vectors must be valid!
  733.  *
  734.  *===========================================================================*/
  735. void
  736. ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx, bmy, bmx, motionBlock)
  737.     MpegFrame *prev;
  738.     MpegFrame *next;
  739.     int by;
  740.     int bx;
  741.     int mode;
  742.     int fmy;
  743.     int fmx;
  744.     int bmy;
  745.     int bmx;
  746.     LumBlock motionBlock;
  747. {
  748.     LumBlock    prevBlock, nextBlock;
  749.     register int    y, x;
  750.  
  751.     switch(mode) {
  752.     case MOTION_FORWARD:
  753.         ComputeMotionLumBlock(prev, by, bx, fmy, fmx, motionBlock);
  754.         break;
  755.     case MOTION_BACKWARD:
  756.         ComputeMotionLumBlock(next, by, bx, bmy, bmx, motionBlock);
  757.         break;
  758.     case MOTION_INTERPOLATE:
  759.         ComputeMotionLumBlock(prev, by, bx, fmy, fmx, prevBlock);
  760.         ComputeMotionLumBlock(next, by, bx, bmy, bmx, nextBlock);
  761.  
  762.         for ( y = 0; y < 16; y++ ) {
  763.         for ( x = 0; x < 16; x++ ) {
  764.             motionBlock[y][x] = (prevBlock[y][x]+nextBlock[y][x]+1)/2;
  765.         }
  766.         }
  767.         break;
  768.     }
  769. }
  770.  
  771.  
  772. /*===========================================================================*
  773.  *
  774.  * EstimateSecondsPerBFrame
  775.  *
  776.  *    estimate the seconds to compute a B-frame
  777.  *
  778.  * RETURNS:    the time, in seconds
  779.  *
  780.  * SIDE EFFECTS:    none
  781.  *
  782.  *===========================================================================*/
  783. float
  784. EstimateSecondsPerBFrame()
  785. {
  786.     if ( numFrames == 0 ) {
  787.     return 20.0;
  788.     } else {
  789.     return (float)totalTime/(60.0*(float)numFrames);
  790.     }
  791. }
  792.  
  793.  
  794. /*=====================*
  795.  * INTERNAL PROCEDURES *
  796.  *=====================*/
  797.  
  798. /*===========================================================================*
  799.  *
  800.  * ComputeBMotionBlock
  801.  *
  802.  *    compute the block resulting from motion compensation
  803.  *
  804.  * RETURNS:    motionBlock is modified
  805.  *
  806.  * SIDE EFFECTS:    none
  807.  *
  808.  * PRECONDITION:    the motion vectors must be valid!
  809.  *
  810.  *===========================================================================*/
  811. static void
  812. ComputeBMotionBlock(prev, next, by, bx, mode, fmy, fmx, bmy, bmx, motionBlock, type)
  813.     MpegFrame *prev;
  814.     MpegFrame *next;
  815.     int by;
  816.     int bx;
  817.     int mode;
  818.     int fmy;
  819.     int fmx;
  820.     int bmy;
  821.     int bmx;
  822.     Block motionBlock;
  823.     int type;
  824. {
  825.     Block    prevBlock, nextBlock;
  826.     register int    y, x;
  827.  
  828.     switch(mode) {
  829.     case MOTION_FORWARD:
  830.         if ( type == LUM_BLOCK ) {
  831.         ComputeMotionBlock(prev->ref_y, by, bx, fmy, fmx, motionBlock);
  832.         } else if ( type == CB_BLOCK ) {
  833.         ComputeMotionBlock(prev->ref_cb, by, bx, fmy, fmx, motionBlock);
  834.         } else if ( type == CR_BLOCK ) {
  835.         ComputeMotionBlock(prev->ref_cr, by, bx, fmy, fmx, motionBlock);
  836.         }
  837.         break;
  838.     case MOTION_BACKWARD:
  839.         if ( type == LUM_BLOCK ) {
  840.         ComputeMotionBlock(next->ref_y, by, bx, bmy, bmx, motionBlock);
  841.         } else if ( type == CB_BLOCK ) {
  842.         ComputeMotionBlock(next->ref_cb, by, bx, bmy, bmx, motionBlock);
  843.         } else if ( type == CR_BLOCK ) {
  844.         ComputeMotionBlock(next->ref_cr, by, bx, bmy, bmx, motionBlock);
  845.         }
  846.         break;
  847.     case MOTION_INTERPOLATE:
  848.         if ( type == LUM_BLOCK ) {
  849.         ComputeMotionBlock(prev->ref_y, by, bx, fmy, fmx, prevBlock);
  850.         ComputeMotionBlock(next->ref_y, by, bx, bmy, bmx, nextBlock);
  851.         } else if ( type == CB_BLOCK ) {
  852.         ComputeMotionBlock(prev->ref_cb, by, bx, fmy, fmx, prevBlock);
  853.         ComputeMotionBlock(next->ref_cb, by, bx, bmy, bmx, nextBlock);
  854.         } else if ( type == CR_BLOCK ) {
  855.         ComputeMotionBlock(prev->ref_cr, by, bx, fmy, fmx, prevBlock);
  856.         ComputeMotionBlock(next->ref_cr, by, bx, bmy, bmx, nextBlock);
  857.         }
  858.  
  859.         for ( y = 0; y < 8; y++ ) {
  860.         for ( x = 0; x < 8; x++ ) {
  861.             motionBlock[y][x] = (prevBlock[y][x]+nextBlock[y][x]+1)/2;
  862.         }
  863.         }
  864.         break;
  865.     }
  866. }
  867.  
  868.  
  869. /*===========================================================================*
  870.  *
  871.  * ComputeBDiffDCTs
  872.  *
  873.  *    compute the DCT of the error term
  874.  *
  875.  * RETURNS:    appropriate blocks of current will contain the DCTs
  876.  *
  877.  * SIDE EFFECTS:    none
  878.  *
  879.  * PRECONDITION:    the motion vectors must be valid!
  880.  *
  881.  *===========================================================================*/
  882. static void
  883. ComputeBDiffDCTs(current, prev, next, by, bx, mode, fmy, fmx, bmy, bmx, pattern)
  884.     MpegFrame *current;
  885.     MpegFrame *prev;
  886.     MpegFrame *next;
  887.     int by;
  888.     int bx;
  889.     int mode;
  890.     int fmy;
  891.     int fmx;
  892.     int bmy;
  893.     int bmx;
  894.     int pattern;
  895. {
  896.     Block   motionBlock;
  897.  
  898.     if ( pattern & 0x20 ) {
  899.     ComputeBMotionBlock(prev, next, by, bx, mode, fmy, fmx,
  900.                 bmy, bmx, motionBlock, LUM_BLOCK);
  901.     ComputeDiffDCTBlock(current->y_blocks[by][bx], motionBlock);
  902.     }
  903.  
  904.     if ( pattern & 0x10 ) {
  905.     ComputeBMotionBlock(prev, next, by, bx+1, mode, fmy, fmx,
  906.                 bmy, bmx, motionBlock, LUM_BLOCK);
  907.     ComputeDiffDCTBlock(current->y_blocks[by][bx+1], motionBlock);
  908.     }
  909.  
  910.     if ( pattern & 0x8 ) {
  911.     ComputeBMotionBlock(prev, next, by+1, bx, mode, fmy, fmx,
  912.                 bmy, bmx, motionBlock, LUM_BLOCK);
  913.     ComputeDiffDCTBlock(current->y_blocks[by+1][bx], motionBlock);
  914.     }
  915.  
  916.     if ( pattern & 0x4 ) {
  917.     ComputeBMotionBlock(prev, next, by+1, bx+1, mode, fmy, fmx,
  918.                 bmy, bmx, motionBlock, LUM_BLOCK);
  919.     ComputeDiffDCTBlock(current->y_blocks[by+1][bx+1], motionBlock);
  920.     }
  921.  
  922.     if ( pattern & 0x2 ) {
  923.     ComputeBMotionBlock(prev, next, by>>1, bx>>1, mode, fmy/2, fmx/2,
  924.                 bmy/2, bmx/2, motionBlock, CB_BLOCK);
  925.     ComputeDiffDCTBlock(current->cb_blocks[by >> 1][bx >> 1], motionBlock);
  926.     }
  927.  
  928.     if ( pattern & 0x1 ) {
  929.     ComputeBMotionBlock(prev, next, by>>1, bx>>1, mode, fmy/2, fmx/2,
  930.                 bmy/2, bmx/2, motionBlock, CR_BLOCK);
  931.     ComputeDiffDCTBlock(current->cr_blocks[by >> 1][bx >> 1], motionBlock);
  932.     }
  933. }
  934.  
  935.  
  936. /*===========================================================================*
  937.  *
  938.  *                USER-MODIFIABLE
  939.  *
  940.  * DoBIntraCode
  941.  *
  942.  *    decides if this block should be coded as intra-block
  943.  *
  944.  * RETURNS:    TRUE if intra-coding should be used; FALSE otherwise
  945.  *
  946.  * SIDE EFFECTS:    none
  947.  *
  948.  * PRECONDITION:    the motion vectors must be valid!
  949.  *
  950.  *===========================================================================*/
  951. static boolean
  952. DoBIntraCode(current, prev, next, by, bx, mode, fmy, fmx, bmy, bmx)
  953.     MpegFrame *current;
  954.     MpegFrame *prev;
  955.     MpegFrame *next;
  956.     int by;
  957.     int bx;
  958.     int mode;
  959.     int fmy;
  960.     int fmx;
  961.     int bmy;
  962.     int bmx;
  963. {
  964.     int        x, y;
  965.     int32 sum = 0, vard = 0, varc = 0, dif;
  966.     int32 currPixel, prevPixel;
  967.     LumBlock    motionBlock;
  968.     int        fy, fx;
  969.  
  970.     ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx,
  971.                bmy, bmx, motionBlock);
  972.  
  973.     MOTION_TO_FRAME_COORD(by, bx, 0, 0, fy, fx);
  974.  
  975.     for ( y = 0; y < 16; y++ ) {
  976.     for ( x = 0; x < 16; x++ ) {
  977.         currPixel = current->orig_y[fy+y][fx+x];
  978.         prevPixel = motionBlock[y][x];
  979.  
  980.         sum += currPixel;
  981.         varc += currPixel*currPixel;
  982.  
  983.         dif = currPixel - prevPixel;
  984.         vard += dif*dif;
  985.     }
  986.     }
  987.  
  988.     vard /= 256;    /* assumes mean is close to zero */
  989.     varc = varc/256 - (sum/256)*(sum/256);
  990.  
  991.     if ( vard <= 64 ) {
  992.     return FALSE;
  993.     } else if ( vard < varc ) {
  994.     return FALSE;
  995.     } else {
  996.     return TRUE;
  997.     }
  998. }
  999.  
  1000. /*===========================================================================*
  1001.  *
  1002.  *                USER-MODIFIABLE
  1003.  *
  1004.  * MotionSufficient
  1005.  *
  1006.  *    decides if this motion vector is sufficient without DCT coding
  1007.  *
  1008.  * RETURNS:    TRUE if no DCT is needed; FALSE otherwise
  1009.  *
  1010.  * SIDE EFFECTS:    none
  1011.  *
  1012.  * PRECONDITION:    the motion vectors must be valid!
  1013.  *
  1014.  *===========================================================================*/
  1015. static boolean
  1016. MotionSufficient(currBlock, prev, next, by, bx, mode, fmy, fmx, bmy, bmx)
  1017.     LumBlock currBlock;
  1018.     MpegFrame *prev;
  1019.     MpegFrame *next;
  1020.     int by;
  1021.     int bx;
  1022.     int mode;
  1023.     int fmy;
  1024.     int fmx;
  1025.     int bmy;
  1026.     int bmx;
  1027. {
  1028.     LumBlock   motionBlock;
  1029.  
  1030.     if ( mode != MOTION_BACKWARD ) {
  1031.     /* check forward motion for bounds */
  1032.     if ( (by*DCTSIZE+(fmy-1)/2 < 0) || ((by+2)*DCTSIZE+(fmy+1)/2-1 >= Fsize_y) ) {
  1033.         return FALSE;
  1034.     }
  1035.     if ( (bx*DCTSIZE+(fmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(fmx+1)/2-1 >= Fsize_x) ) {
  1036.         return FALSE;
  1037.     }
  1038.     }
  1039.  
  1040.     if ( mode != MOTION_FORWARD ) {
  1041.     /* check backward motion for bounds */
  1042.     if ( (by*DCTSIZE+(bmy-1)/2 < 0) || ((by+2)*DCTSIZE+(bmy+1)/2-1 >= Fsize_y) ) {
  1043.         return FALSE;
  1044.     }
  1045.     if ( (bx*DCTSIZE+(bmx-1)/2 < 0) || ((bx+2)*DCTSIZE+(bmx+1)/2-1 >= Fsize_x) ) {
  1046.         return FALSE;
  1047.     }
  1048.     }
  1049.  
  1050.     ComputeBMotionLumBlock(prev, next, by, bx, mode, fmy, fmx,
  1051.                bmy, bmx, motionBlock);
  1052.  
  1053.     return (LumBlockMAD(currBlock, motionBlock, 0x7fffffff) <= 512);
  1054. }
  1055.